package com.miku.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.miku.blog.domain.*;
import com.miku.blog.domain.dto.MenuDTO;
import com.miku.blog.domain.pojo.LoginUser;
import com.miku.blog.domain.pojo.ResponseResult;
import com.miku.blog.domain.pojo.SystemConstance;
import com.miku.blog.domain.vo.MenuVo;
import com.miku.blog.eume.HttpStatusEnum;
import com.miku.blog.exception.SystemException;
import com.miku.blog.mapper.RoleMapper;
import com.miku.blog.service.MenuService;
import com.miku.blog.mapper.MenuMapper;
import com.miku.blog.service.RoleService;
import com.miku.blog.utils.BeanCopyUtils;
import com.miku.blog.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author Miku
 * @description 针对表【tb_menu】的数据库操作Service实现
 * @createDate 2022-05-25 19:18:26
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu>
        implements MenuService {

    @Lazy
    @Autowired
    private RoleService roleService;

    @Override
    public ResponseResult userMenus() {
        LoginUser loginUser = SecurityUtils.getLoginUser();

        List<Menu> rootMenus = baseMapper.getRootMenus(loginUser.getUserAuth().getId());
        List<MenuVo> menuVoList = null;
        if (Objects.nonNull(rootMenus) && rootMenus.size() > 0) {
            menuVoList
                    = rootMenus.stream()
                    .map(menu -> {
                        MenuVo menuVo = BeanCopyUtils.copyObjectByType(menu, MenuVo.class);
                        if (menu.getIsHidden().equals(SystemConstance.NOT_HIDDEN)) {
                            menuVo.setHidden(false);
                        } else {
                            menuVo.setHidden(true);
                        }
                        return menuVo;
                    }).collect(Collectors.toList());

            LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
            menuVoList
                    = menuVoList.stream()
                    .map(vo -> {
                        queryWrapper.clear();
                        queryWrapper.eq(Menu::getParentId, vo.getId())
                                .orderByAsc(Menu::getOrderNum)
                                .orderByDesc(Menu::getCreateTime);
                        List<Menu> var1 = list(queryWrapper);
                        if (Objects.nonNull(var1) && var1.size() > 0) {
                            List<MenuVo> collect
                                    = var1.stream()
                                    .map(var11 -> {
                                        MenuVo menuVo = BeanCopyUtils.copyObjectByType(var11, MenuVo.class);
                                        if (var11.getIsHidden().equals(SystemConstance.NOT_HIDDEN)) {
                                            menuVo.setHidden(false);
                                        } else {
                                            menuVo.setHidden(true);
                                        }
                                        return menuVo;
                                    }).collect(Collectors.toList());
                            vo.setChildren(collect);
                        }
                        return vo;
                    })
                    .collect(Collectors.toList());
        }

        return ResponseResult.ok().setData(menuVoList);
    }


    @Override
    public ResponseResult getMenus() {
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Menu::getParentId, SystemConstance.MENU_ROOT_ID)
                .orderByAsc(Menu::getOrderNum)
                .orderByDesc(Menu::getCreateTime);
        List<Menu> rootMenus = list(queryWrapper);
        List<MenuDTO> menuDTOList = null;
        if (Objects.nonNull(rootMenus) && rootMenus.size() > 0) {
            menuDTOList
                    = rootMenus.stream()
                    .map(menu -> {
                        MenuDTO menuDTO
                                = new MenuDTO()
                                .setId(menu.getId())
                                .setLabel(menu.getName());
                        queryWrapper.clear();
                        queryWrapper.eq(Menu::getParentId, menu.getId())
                                .orderByAsc(Menu::getOrderNum)
                                .orderByDesc(Menu::getCreateTime);
                        List<Menu> var1 = list(queryWrapper);
                        if (Objects.nonNull(var1) && var1.size() > 0) {
                            List<MenuDTO> children
                                    = var1.stream()
                                    .map(var11 -> {
                                        MenuDTO var12 = new MenuDTO();
                                        var12.setId(var11.getId())
                                                .setLabel(var11.getName());
                                        return var12;
                                    }).collect(Collectors.toList());

                            menuDTO.setChildren(children);
                        }
                        return menuDTO;
                    }).collect(Collectors.toList());
        }
        return ResponseResult.ok().setData(menuDTOList);
    }


    @Override
    public ResponseResult getMenuList(@Nullable String keywords) {
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Menu::getParentId, SystemConstance.MENU_ROOT_ID)
                .like(StringUtils.hasText(keywords), Menu::getName, keywords)
                .orderByAsc(Menu::getOrderNum)
                .orderByDesc(Menu::getCreateTime);
        List<Menu> rootMenus = list(queryWrapper);
        if (Objects.nonNull(rootMenus) && rootMenus.size() > 0) {
            rootMenus = rootMenus.stream()
                    .map(root -> {
                        queryWrapper.clear();
                        queryWrapper.eq(Menu::getParentId, root.getId())
                                .orderByAsc(Menu::getOrderNum)
                                .orderByDesc(Menu::getCreateTime);
                        List<Menu> children = list(queryWrapper);
                        if (Objects.nonNull(children) || children.size() > 0) {
                            root.setChildren(children);
                        }
                        return root;
                    }).collect(Collectors.toList());
        }

        return ResponseResult.ok().setData(rootMenus);
    }


    @Override
    public ResponseResult isHidden(Integer menuId, Integer isHidden) {
        if ((!isHidden.equals(SystemConstance.IS_HIDDEN) && !isHidden.equals(SystemConstance.NOT_HIDDEN))
        ) {
            return new ResponseResult(HttpStatusEnum.PARAM_ERROR);
        }
        LambdaUpdateWrapper<Menu> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Menu::getId, menuId)
                .set(Menu::getIsHidden, isHidden)
                .set(Menu::getUpdateTime,new Date());
        if (!update(updateWrapper)) {
            return new ResponseResult(HttpStatusEnum.UPDATE_DATA_ERROR);
        }
        return ResponseResult.ok();
    }


    @Override
    public ResponseResult updateMenu(Menu menu) {

        String icon = menu.getIcon();
        Integer isHidden = menu.getIsHidden();
        Integer orderNum = menu.getOrderNum();
        String name = menu.getName();
        String path = menu.getPath();
        if (Objects.isNull(isHidden) || Objects.isNull(orderNum)
                || !StringUtils.hasText(name) || !StringUtils.hasText(path) || !StringUtils.hasText(icon)
                || (!isHidden.equals(SystemConstance.IS_HIDDEN) && !isHidden.equals(SystemConstance.NOT_HIDDEN))
                || !(orderNum >= SystemConstance.ORDERNUM_MIN && orderNum <= SystemConstance.ORDERNUM_MAX)
        ) {
            return new ResponseResult(HttpStatusEnum.PARAM_ERROR);
        }

        if (!SystemConstance.iconList.contains(icon)) {
            return new ResponseResult(HttpStatusEnum.ICON_TYPE_ERROR);
        }

        Integer parentId = menu.getParentId();
        Integer menuId = menu.getId();
        if (Objects.nonNull(menuId)) {
            //若menuId不为NULL, 则表示此次是修改行为
            if (Objects.isNull(parentId) || !StringUtils.hasText(menu.getComponent())
            ) {
                return new ResponseResult(HttpStatusEnum.PARAM_ERROR);
            }
            if (!updateById(menu)) {
                return new ResponseResult(HttpStatusEnum.UPDATE_DATA_ERROR);
            }
        } else {
            //若menuId为NULL, 则表示此次是新增行为
            if (Objects.nonNull(parentId)) {
                //若parentId不为NULL, 则表示此次是新增子菜单
                if (!StringUtils.hasText(menu.getComponent())) {
                    return new ResponseResult(HttpStatusEnum.PARAM_ERROR);
                }
            } else {
                //若parentId为NULL, 则表示此次是新增主菜单
                menu.setComponent(SystemConstance.COMPONENT_INIT_NAME);
            }
            if (!save(menu)) {
                return new ResponseResult(HttpStatusEnum.INSERT_DATA_ERROR);
            }

        }

        return ResponseResult.ok();
    }


    @Transactional
    @Override
    public ResponseResult deleteMenu(Integer menuId) {

        RoleMapper roleMapper = (RoleMapper) roleService.getBaseMapper();
        Menu menu = getById(menuId);
        if (menu.getParentId().equals(SystemConstance.MENU_ROOT_ID)) {
            //若删除的是root菜单,则连同菜单一起删除
            LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Menu::getParentId, menuId);
            List<Menu> menuList = list(queryWrapper);
            if (Objects.nonNull(menuList) && menuList.size() > 0) {
                menuList.stream()
                        .peek(var1 -> {
                            Integer id = var1.getId();
                            roleMapper.deleteTBRoleMenuByMenuId(id);
                            if (!removeById(id)) {
                                throw new SystemException(HttpStatusEnum.REMOVE_DATA_ERROR);
                            }
                        })
                        .collect(Collectors.toList());
            }

        }

        roleMapper.deleteTBRoleMenuByMenuId(menuId);
        if (!removeById(menuId)) {
            throw new SystemException(HttpStatusEnum.REMOVE_DATA_ERROR);
        }

        return ResponseResult.ok();
    }
}




